package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.mapper.*;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.strategy.PaidRecordStrategy;
import com.atguigu.tingshu.user.strategy.fac.StrategyFactory;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    /**
     * 提供给小程序微信登录接口
     *
     * @param code 小程序集成SDK后获取临时票据（基于当前微信用户产生的）
     * @return
     */
    @Override
    public Map<String, String> wxLogin(String code) {
        try {
            //1.根据小程序提交code再加appid+appsecret获取微信账户唯一标识 wxOpenId
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
            String wxOpenid = sessionInfo.getOpenid();
            if (StringUtils.isBlank(wxOpenid)) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //2.根据微信唯一标识查询用户记录
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserInfo::getWxOpenId, wxOpenid);
            UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);

            //3.判断用户记录是否存在(用户是否绑定过该微信账号)
            if (userInfo == null) {
                //TODO 如果不存在，新增用户记录绑定微信账户唯一标识，隐式初始化账户记录
                //3.1 构建保存用户信息记录绑定微信唯一标识
                userInfo = new UserInfo();
                userInfo.setWxOpenId(wxOpenid);
                userInfo.setNickname("听友" + IdUtil.getSnowflakeNextId());
                userInfo.setAvatarUrl("https://thirdwx.qlogo.cn/mmopen/vi_32/hFKeRpRQU4wG…axvke5nueicggowdBricR4pspWbp6dwFtLSCWJKyZGJoQ/132");
                userInfoMapper.insert(userInfo);
                //3.2 隐式初始化账户记录
                //3.2.1 构建初始化账户所需参数对象
                Map<String, Object> mapData = new HashMap<>();
                mapData.put("userId", userInfo.getId());
                mapData.put("title", "首次登录赠送体验金");
                mapData.put("amount", new BigDecimal("10"));
                mapData.put("orderNo", "zs" + IdUtil.getSnowflakeNextId());
                //3.2.2 调用发送消息工具类方法发送消息
                rabbitService.sendMessage(MqConst.EXCHANGE_USER, MqConst.ROUTING_USER_REGISTER, mapData);
            }
            //4.为用户生成令牌存入Redis 其中Redis中Key=前缀+token Value=用户基本信息UserInfoVo
            //4.1 生成token值
            String token = IdUtil.randomUUID();
            //4.2 构建用户登录Key 形式=user:login:token值
            String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            //4.3 将用户登录信息UserInfoVo存入Redis
            UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
            redisTemplate.opsForValue().set(loginKey, userInfoVo, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);

            //5.封装token到对象响应给前端
            Map<String, String> map = new HashMap<>();
            map.put("token", token);
            return map;
        } catch (Exception e) {
            log.error("[用户服务]微信登录接口异常：{}", e);
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }
    }

    /**
     * 获取指定用户基本信息
     *
     * @return
     */
    @Override
    public UserInfoVo getUserInfo(Long userId) {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo != null) {
            UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
            return userInfoVo;
        }
        return null;
    }

    /**
     * 更新用户基本信息（昵称、头像）
     *
     * @param userId
     * @param userInfoVo
     */
    @Override
    public void updateUser(Long userId, UserInfoVo userInfoVo) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(userId);
        userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());
        userInfo.setNickname(userInfoVo.getNickname());
        userInfoMapper.updateById(userInfo);


    }

    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;

    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;

    /**
     * 检查提交声音ID列表购买情况
     *
     * @param userId                    用户ID
     * @param albumId                   专辑ID
     * @param needCheckBuyStateTrackIds 待检查购买情况声音ID列表
     * @return 提交待检查购买情况，声音ID购买结果 {38679:1,38678:0}
     */
    @Override
    public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds) {
        Map<Long, Integer> map = new HashMap<>();
        //1.根据用户ID+专辑ID查询专辑购买记录
        LambdaQueryWrapper<UserPaidAlbum> userPaidAlbumLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getAlbumId, albumId);
        userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getUserId, userId);
        Long count = userPaidAlbumMapper.selectCount(userPaidAlbumLambdaQueryWrapper);
        //1.1 存在购买记录
        if (count > 0) {
            for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
                //1.1 将所有提交待检查声音ID购买情况设置1
                map.put(needCheckBuyStateTrackId, 1);
            }
            return map;
        }

        //2.根据用户ID+专辑ID查询已购声音表
        LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getUserId, userId);
        userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getAlbumId, albumId);
        userPaidTrackLambdaQueryWrapper.select(UserPaidTrack::getTrackId);
        List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(userPaidTrackLambdaQueryWrapper);
        if (CollectionUtil.isEmpty(userPaidTrackList)) {
            //2.1 如果不存在已购声音 将所有提交待检查声音ID购买情况设置0返回
            for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
                map.put(needCheckBuyStateTrackId, 0);
            }
            return map;
        }
        //2.2 存在已购声音，遍历待检查声音ID列表判断找出已购声音购买情况设置1，未购买声音购买情况设置为0
        List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
        for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
            //判断已购声音ID列表中是否存在待检查声音ID
            if (userPaidTrackIdList.contains(needCheckBuyStateTrackId)) {
                map.put(needCheckBuyStateTrackId, 1);
            } else {
                map.put(needCheckBuyStateTrackId, 0);
            }
        }
        return map;
    }

    /**
     * 查询当前用户是否购买指定专辑
     *
     * @param albumId
     * @return
     */
    @Override
    public Boolean isPaidAlbum(Long albumId) {
        Long userId = AuthContextHolder.getUserId();
        LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPaidAlbum::getUserId, userId);
        queryWrapper.eq(UserPaidAlbum::getAlbumId, albumId);
        return userPaidAlbumMapper.selectCount(queryWrapper) > 0;
    }

    /**
     * 查询当前用户某个专辑下已购声音ID列表
     *
     * @param albumId 专辑ID
     * @return 已购声音ID列表
     */
    @Override
    public List<Long> getUserPaidTrackIdList(Long userId, Long albumId) {
        LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPaidTrack::getUserId, userId);
        queryWrapper.eq(UserPaidTrack::getAlbumId, albumId);
        //只需要获取已购声音ID
        queryWrapper.select(UserPaidTrack::getTrackId);
        List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(userPaidTrackList)) {
            return userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
        }
        return null;
    }

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private UserVipServiceMapper userVipServiceMapper;

    @Autowired
    private VipServiceConfigMapper vipServiceConfigMapper;

    @Autowired
    private StrategyFactory strategyFactory;

    /**
     * 保存用户不同购买项目类型的购买记录
     *
     * @param userPaidRecordVo
     */
    @Override
    public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
        //1001-专辑 1002-声音 1003-vip会员
        String itemType = userPaidRecordVo.getItemType();
        PaidRecordStrategy strategy = strategyFactory.getStrategy(itemType);
        strategy.handlerPaidRecord(userPaidRecordVo);
    }

    /**
     * 更新VIP状态：处理过期会员
     *
     * @return
     */
    @Override
    public void updateVipExpireStatus(Date date) {
        //1.查询所有VIP会员
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserInfo::getIsVip, 1);
        List<UserInfo> userInfoList = this.list(queryWrapper);

        //2.判断会员是否过期，如果过期将会员标识修改为0
        if (CollectionUtil.isNotEmpty(userInfoList)) {
            for (UserInfo userInfo : userInfoList) {
                Date vipExpireTime = userInfo.getVipExpireTime();
                if(vipExpireTime.before(date)){
                    userInfo.setIsVip(0);
                    this.updateById(userInfo);
                }
            }
        }
    }
}
